﻿//
// ParallelGrep
//
// Copyright (C) 2011 - Tatsuya Niioka
//
using System;
using System.Windows;
using System.Windows.Input;
using GrepEngine;
using System.IO;
using ParallelGrep.Worker;
using ParallelGrep.Model;
using ParallelGrep.Properties;
using System.Text.RegularExpressions;

namespace ParallelGrep.ViewModel
{
    /// <summary>
    /// オペレーションViewModel
    /// </summary>
    public class OperationViewModel : ViewModel
    {
        private MainViewModel m_mainViewModel;

        #region IsRunner
        /// <summary>
        /// 実行状況を取得します。
        /// </summary>
        public bool IsRunner
        {
            get
            {
                return m_mainViewModel.IsRunner;
            }
        }
        #endregion

        #region IsEnabled
        /// <summary>
        /// 有効状況を取得します。
        /// </summary>
        public bool IsEnabled
        {
            get
            {
                return m_mainViewModel.IsEnabled;
            }
        }
        #endregion

        #region Constructor
        /// <summary>
        /// 指定したMainViewModelで新しい<see cref="OperationViewModel"/>クラスを生成します。
        /// </summary>
        /// <param name="mainViewModel">MainViewModel</param>
        public OperationViewModel(MainViewModel mainViewModel)
        {
            m_mainViewModel = mainViewModel;
        }
        #endregion

        #region worker
        private GrepWorker m_worker = null;
        /// <summary>
        /// ワーカーを取得します。
        /// </summary>
        internal GrepWorker Worker
        {
            get {
                if (m_worker == null)
                {
                    m_worker = new GrepWorker(m_mainViewModel.Info);
                    m_worker.OnProgress += new EventHandler<GrepWorkerProgressEventArgs>(Worker_OnProgress);
                    m_worker.OnGreped += new EventHandler<GrepWorkerGrepedEventArgs>(Worker_OnGreped);
                    m_worker.OnCompleted += new EventHandler<GrepWorkerCompletedEventArgs>(Worker_OnCompleted);
                }
                return m_worker; 
            }
        }
        #endregion

        #region ExecuteCommand
        private RelayCommand m_executeCommand;
        /// <summary>
        /// 実行コマンドを取得します。
        /// </summary>
        public ICommand ExecuteCommand
        {
            get
            {
                if (m_executeCommand == null)
                {
                    m_executeCommand = new RelayCommand(param => this.Execute());
                }
                return m_executeCommand;
            }
        }
        #endregion

        #region Execute
        /// <summary>
        /// 実行します。
        /// </summary>
        public void Execute()
        {
            if (m_mainViewModel.Process == GrepMode.Grep.ToString())
            {
                if (!GrepCheck())
                {
                    return;
                }
            }
            else if (m_mainViewModel.Process == GrepMode.Replace.ToString())
            {
                if (!ReplaceCheck())
                {
                    return;
                }
            }
            else if (m_mainViewModel.Process == GrepMode.Delete.ToString())
            {
                if (!DeleteCheck())
                {
                    return;
                }
            }
            else if (m_mainViewModel.Process == GrepMode.CharCode.ToString())
            {
                if (!CharCodeConvertCheck())
                {
                    return;
                }
            }
            else if (m_mainViewModel.Process == GrepMode.Indent.ToString())
            {
                if (!IndentConvertCheck())
                {
                    return;
                }
            }
            else if (m_mainViewModel.Process == GrepMode.Trim.ToString())
            {
                if (!LineTrimCheck())
                {
                    return;
                }
            }

            m_mainViewModel.IsRunner = true;
            OnPropertyChanged("IsRunner");
            OnPropertyChanged("IsEnabled");

            if (m_mainViewModel.Process == GrepMode.Grep.ToString() ||
                m_mainViewModel.Process == GrepMode.Replace.ToString() ||
                m_mainViewModel.Process == GrepMode.Delete.ToString())
            {
                Regex = Grep.GetRegex(m_mainViewModel.SearchValue,
                                            m_mainViewModel.IsWord,
                                            m_mainViewModel.IsIgnoreCase,
                                            m_mainViewModel.IsConditions,
                                            (ConditionsMode)Enum.Parse(typeof(ConditionsMode), m_mainViewModel.ConditionsMode));
            }


            m_mainViewModel.ProgressViewModel.Clear();
            Worker.RunWorkerAsync();
        }

        private void Worker_OnProgress(object sender, GrepWorkerProgressEventArgs e)
        {
            m_mainViewModel.StatusBarText = string.Format(Resources.ProgressFileMessage, e.FileName);
        }

        #endregion

        #region Worker_OnGreped
        /// <summary>
        /// 指定したイベント送信オブジェクト、イベントデータで実行します。
        /// </summary>
        /// <param name="sender">イベント送信オブジェクト</param>
        /// <param name="e">イベントデータ</param>
        private void Worker_OnGreped(object sender, GrepWorkerGrepedEventArgs e)
        {
            var pInfo = new ProgressInfo();
            var fInfo = new FileInfo(e.FileName);
            pInfo.FileName = fInfo.Name;
            pInfo.Path = fInfo.DirectoryName;
            pInfo.LineNumber = e.LineNumber;
            pInfo.ColumnIndex = e.ColumnIndex;
            pInfo.Size = e.Size;
            pInfo.Encoding = e.Encoding;
            pInfo.Text = e.Text;
            var dispatcher = App.Current.Dispatcher;
            dispatcher.BeginInvoke(new Action<ProgressInfo>(m_mainViewModel.ProgressViewModel.Add), pInfo);
        }
        #endregion

        #region Worker_OnCompleted
        /// <summary>
        /// 指定したイベント送信オブジェクト、イベントデータで実行します。
        /// </summary>
        /// <param name="sender">イベント送信オブジェクト</param>
        /// <param name="e">イベントデータ</param>
        private void Worker_OnCompleted(object sender, GrepWorkerCompletedEventArgs e)
        {
            if (e.Cancel)
            {
                m_mainViewModel.StatusBarText = Resources.CompletedCancelMessage;
            }
            else
            {
                m_mainViewModel.StatusBarText = string.Format(Resources.CompletedMessage, e.FileCount);
            }
            m_mainViewModel.IsRunner = false;
            OnPropertyChanged("IsRunner");
            OnPropertyChanged("IsEnabled");
        }
        #endregion

        #region Regex
        private Regex m_regex;
        /// <summary>
        /// 正規表現を取得または設定します。
        /// </summary>
        public Regex Regex
        {
            get { return m_regex; }
            set {
                if (m_regex != null)
                {
                    if (m_regex.Equals(value))
                    {
                        return;
                    }
                }
                m_regex = value;
                OnPropertyChanged("Regex");
            }
        }
        #endregion

        #region GrepCheck
        /// <summary>
        /// 検索チェックを実行します。
        /// </summary>
        /// <returns>正常な場合はtrue、エラーの場合はfalseを戻します。</returns>
        public bool GrepCheck()
        {
            if (string.IsNullOrWhiteSpace(m_mainViewModel.Path))
            {
                MessageBox.Show(Resources.ErrorConfirmInputPathEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (!Directory.Exists(m_mainViewModel.Path))
            {
                MessageBox.Show(Resources.ErrorConfirmInputPathNotExists, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (string.IsNullOrWhiteSpace(m_mainViewModel.SearchValue))
            {
                MessageBox.Show(Resources.ErrorConfirmSearchValueEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (string.IsNullOrWhiteSpace(m_mainViewModel.SearchPattern))
            {
                MessageBox.Show(Resources.ErrorConfirmSearchPatternEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            return true;
        }
        #endregion

        #region ReplaceCheck
        /// <summary>
        /// 置換チェックを実行します。
        /// </summary>
        /// <returns>正常な場合はtrue、エラーの場合はfalseを戻します。</returns>
        public bool ReplaceCheck()
        {
            if (string.IsNullOrWhiteSpace(m_mainViewModel.Path))
            {
                MessageBox.Show(Resources.ErrorConfirmInputPathEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (!Directory.Exists(m_mainViewModel.Path))
            {
                MessageBox.Show(Resources.ErrorConfirmInputPathNotExists, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (string.IsNullOrWhiteSpace(m_mainViewModel.SearchValue))
            {
                MessageBox.Show(Resources.ErrorConfirmSearchValueEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (string.IsNullOrWhiteSpace(m_mainViewModel.SearchPattern))
            {
                MessageBox.Show(Resources.ErrorConfirmSearchPatternEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (m_mainViewModel.Process == GrepMode.Replace.ToString())
            {
                if (string.IsNullOrWhiteSpace(m_mainViewModel.ReplaceViewModel.ReplacementValue))
                {
                    MessageBox.Show(Resources.ErrorConfirmReplacementValueEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                    return false;
                }
            }
            if (m_mainViewModel.IsOutputPath)
            {
                if (string.IsNullOrWhiteSpace(m_mainViewModel.OutputPath))
                {
                    MessageBox.Show(Resources.ErrorConfirmOutputPathEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                    return false;
                }
                if (!Directory.Exists(m_mainViewModel.OutputPath))
                {
                    MessageBox.Show(Resources.ErrorConfirmOutputPathNotExists, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                    return false;
                }
            }
            return true;
        }
        #endregion

        #region DeleteCheck
        /// <summary>
        /// 削除チェックを実行します。
        /// </summary>
        /// <returns>正常な場合はtrue、エラーの場合はfalseを戻します。</returns>
        public bool DeleteCheck()
        {
            if (string.IsNullOrWhiteSpace(m_mainViewModel.Path))
            {
                MessageBox.Show(Resources.ErrorConfirmInputPathEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (!Directory.Exists(m_mainViewModel.Path))
            {
                MessageBox.Show(Resources.ErrorConfirmInputPathNotExists, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (string.IsNullOrWhiteSpace(m_mainViewModel.SearchValue))
            {
                MessageBox.Show(Resources.ErrorConfirmSearchValueEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (string.IsNullOrWhiteSpace(m_mainViewModel.SearchPattern))
            {
                MessageBox.Show(Resources.ErrorConfirmSearchPatternEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (m_mainViewModel.IsOutputPath)
            {
                if (string.IsNullOrWhiteSpace(m_mainViewModel.OutputPath))
                {
                    MessageBox.Show(Resources.ErrorConfirmOutputPathEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                    return false;
                }
                if (!Directory.Exists(m_mainViewModel.OutputPath))
                {
                    MessageBox.Show(Resources.ErrorConfirmOutputPathNotExists, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                    return false;
                }
            }
            return true;
        }
        #endregion

        #region CharCodeConvertCheck
        /// <summary>
        /// 文字コード変換チェックを実行します。
        /// </summary>
        /// <returns>正常な場合はtrue、エラーの場合はfalseを戻します。</returns>
        public bool CharCodeConvertCheck()
        {
            if (string.IsNullOrWhiteSpace(m_mainViewModel.Path))
            {
                MessageBox.Show(Resources.ErrorConfirmInputPathEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (!Directory.Exists(m_mainViewModel.Path))
            {
                MessageBox.Show(Resources.ErrorConfirmInputPathNotExists, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (string.IsNullOrWhiteSpace(m_mainViewModel.SearchPattern))
            {
                MessageBox.Show(Resources.ErrorConfirmSearchPatternEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (m_mainViewModel.CharCodeConvertViewModel.OutputEncodingName == "None" &&
                m_mainViewModel.CharCodeConvertViewModel.OutputLineEnd == "None")
            {
                MessageBox.Show(Resources.ErrorConfirmOutputEncodingOrLineEnd, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (m_mainViewModel.IsOutputPath)
            {
                if (string.IsNullOrWhiteSpace(m_mainViewModel.OutputPath))
                {
                    MessageBox.Show(Resources.ErrorConfirmOutputPathEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                    return false;
                }
                if (!Directory.Exists(m_mainViewModel.OutputPath))
                {
                    MessageBox.Show(Resources.ErrorConfirmOutputPathNotExists, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                    return false;
                }
            }
            return true;
        }
        #endregion

        #region IndentConvertCheck
        /// <summary>
        /// インデント変換チェックを実行します。
        /// </summary>
        /// <returns>正常な場合はtrue、エラーの場合はfalseを戻します。</returns>
        public bool IndentConvertCheck()
        {
            if (string.IsNullOrWhiteSpace(m_mainViewModel.Path))
            {
                MessageBox.Show(Resources.ErrorConfirmInputPathEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (!Directory.Exists(m_mainViewModel.Path))
            {
                MessageBox.Show(Resources.ErrorConfirmInputPathNotExists, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (string.IsNullOrWhiteSpace(m_mainViewModel.SearchPattern))
            {
                MessageBox.Show(Resources.ErrorConfirmSearchPatternEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (m_mainViewModel.IsOutputPath)
            {
                if (string.IsNullOrWhiteSpace(m_mainViewModel.OutputPath))
                {
                    MessageBox.Show(Resources.ErrorConfirmOutputPathEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                    return false;
                }
                if (!Directory.Exists(m_mainViewModel.OutputPath))
                {
                    MessageBox.Show(Resources.ErrorConfirmOutputPathNotExists, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                    return false;
                }
            }
            return true;
        }
        #endregion

        #region LineTrimCheck
        /// <summary>
        /// 行末Trimを実行します。
        /// </summary>
        /// <returns>正常な場合はtrue、エラーの場合はfalseを戻します。</returns>
        public bool LineTrimCheck()
        {
            if (string.IsNullOrWhiteSpace(m_mainViewModel.Path))
            {
                MessageBox.Show(Resources.ErrorConfirmInputPathEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (!Directory.Exists(m_mainViewModel.Path))
            {
                MessageBox.Show(Resources.ErrorConfirmInputPathNotExists, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (string.IsNullOrWhiteSpace(m_mainViewModel.SearchPattern))
            {
                MessageBox.Show(Resources.ErrorConfirmSearchPatternEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            if (m_mainViewModel.IsOutputPath)
            {
                if (string.IsNullOrWhiteSpace(m_mainViewModel.OutputPath))
                {
                    MessageBox.Show(Resources.ErrorConfirmOutputPathEmpty, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                    return false;
                }
                if (!Directory.Exists(m_mainViewModel.OutputPath))
                {
                    MessageBox.Show(Resources.ErrorConfirmOutputPathNotExists, Resources.ErrorConfirmTitle, MessageBoxButton.OK, MessageBoxImage.Error);
                    return false;
                }
            }
            return true;
        }
        #endregion

        #region CancelCommand
        private RelayCommand m_cancelCommand;
        /// <summary>
        /// キャンセルコマンドを取得します。
        /// </summary>
        public ICommand CancelCommand
        {
            get
            {
                if (m_cancelCommand == null)
                {
                    m_cancelCommand = new RelayCommand(param => this.Cancel());
                }
                return m_cancelCommand;
            }
        }
        #endregion

        #region Cancel
        /// <summary>
        /// キャンセルします。
        /// </summary>
        public void Cancel()
        {
            if (m_mainViewModel.IsRunner)
            {
                if (MessageBox.Show(Resources.CancelConfirm, Resources.CancelConfirmTitle, MessageBoxButton.OKCancel, MessageBoxImage.Error) == MessageBoxResult.OK)
                {
                    Worker.CancelAsync();
                }
            }
        }
        #endregion

        #region ClearHistoryCommand
        private RelayCommand m_clearHistoryCommand;
        /// <summary>
        /// 履歴クリアコマンドを取得します。
        /// </summary>
        public ICommand ClearHistoryCommand
        {
            get
            {
                if (m_clearHistoryCommand == null)
                {
                    m_clearHistoryCommand = new RelayCommand(param => this.ClearHistory());
                }
                return m_clearHistoryCommand;
            }
        }
        #endregion

        #region ClearHistory
        /// <summary>
        /// 履歴をクリアします。
        /// </summary>
        public void ClearHistory()
        {
            m_mainViewModel.Paths.Clear();
            m_mainViewModel.SearchPatterns.Clear();
            m_mainViewModel.SearchValues.Clear();
            m_mainViewModel.ReplaceViewModel.ReplacementValues.Clear();
        }
        #endregion

    }
}
